From 46a5fe9a41522e0b979d587fd72cbd4011e2d875 Mon Sep 17 00:00:00 2001 From: Nipunn Koorapati Date: Mon, 4 Sep 2017 17:13:26 -0700 Subject: [PATCH] Hashed dependencies of metadata into the metadata of a lib --- src/cargo/ops/cargo_rustc/context.rs | 12 +++- tests/workspaces.rs | 91 ++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 906a5155a..ffce9680b 100755 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -82,7 +82,7 @@ impl TargetInfo { } } -#[derive(Clone)] +#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] pub struct Metadata(u64); impl<'a, 'cfg> Context<'a, 'cfg> { @@ -483,6 +483,16 @@ impl<'a, 'cfg> Context<'a, 'cfg> { // when changing feature sets each lib is separately cached. self.resolve.features_sorted(unit.pkg.package_id()).hash(&mut hasher); + if let Ok(dep_units) = self.dep_targets(&unit) { + let mut dep_metadatas = dep_units.into_iter().map(|dep_unit| { + self.target_metadata(&dep_unit) + }).collect::>(); + dep_metadatas.sort(); + for metadata in dep_metadatas { + metadata.hash(&mut hasher); + } + } + // Throw in the profile we're compiling with. This helps caching // panic=abort and panic=unwind artifacts, additionally with various // settings like debuginfo and whatnot. diff --git a/tests/workspaces.rs b/tests/workspaces.rs index 1228ae282..215af77ec 100644 --- a/tests/workspaces.rs +++ b/tests/workspaces.rs @@ -1465,3 +1465,94 @@ Caused by: ")); } +/// This is a freshness test for feature use with workspaces +/// +/// feat_lib is used by caller1 and caller2, but with different features enabled. +/// This test ensures that alternating building caller1, caller2 doesn't force +/// recompile of feat_lib. +/// +/// Ideally once we solve https://github.com/rust-lang/cargo/issues/3620, then +/// a single cargo build at the top level will be enough. +#[test] +fn dep_used_with_separate_features() { + let p = project("foo") + .file("Cargo.toml", r#" + [workspace] + members = ["feat_lib", "caller1", "caller2"] + "#) + .file("feat_lib/Cargo.toml", r#" + [project] + name = "feat_lib" + version = "0.1.0" + authors = [] + + [features] + myfeature = [] + "#) + .file("feat_lib/src/lib.rs", "") + .file("caller1/Cargo.toml", r#" + [project] + name = "caller1" + version = "0.1.0" + authors = [] + + [dependencies] + feat_lib = { path = "../feat_lib" } + "#) + .file("caller1/src/main.rs", "fn main() {}") + .file("caller1/src/lib.rs", "") + .file("caller2/Cargo.toml", r#" + [project] + name = "caller2" + version = "0.1.0" + authors = [] + + [dependencies] + feat_lib = { path = "../feat_lib", features = ["myfeature"] } + caller1 = { path = "../caller1" } + "#) + .file("caller2/src/main.rs", "fn main() {}") + .file("caller2/src/lib.rs", ""); + p.build(); + + // Build the entire workspace + assert_that(p.cargo("build"), + execs().with_status(0) + .with_stderr("\ +[..]Compiling feat_lib v0.1.0 ([..]) +[..]Compiling caller1 v0.1.0 ([..]) +[..]Compiling caller2 v0.1.0 ([..]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +")); + assert_that(&p.bin("caller1"), existing_file()); + assert_that(&p.bin("caller2"), existing_file()); + + + // Build caller1. should build the dep library. Because the features + // are different than the full workspace, it rebuilds. + assert_that(p.cargo("build").cwd(p.root().join("caller1")), + execs().with_status(0) + .with_stderr("\ +[..]Compiling feat_lib v0.1.0 ([..]) +[..]Compiling caller1 v0.1.0 ([..]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +")); + + // Alternate building caller2/caller1 a few times, just to make sure + // features are being built separately. Should not rebuild anything + assert_that(p.cargo("build").cwd(p.root().join("caller2")), + execs().with_status(0) + .with_stderr("\ +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +")); + assert_that(p.cargo("build").cwd(p.root().join("caller1")), + execs().with_status(0) + .with_stderr("\ +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +")); + assert_that(p.cargo("build").cwd(p.root().join("caller2")), + execs().with_status(0) + .with_stderr("\ +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +")); +} -- 2.30.2